home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / games / IndiZone / cycles / mcast-io.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  13.7 KB  |  595 lines

  1. #include <stdlib.h>
  2. #include <bstring.h>    /* for bcopy */
  3. #include <string.h>    /* for strcmp */
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. #include <sys/uio.h>    /* for iovec */
  8. #include <sys/mbuf.h>    /* for mbuf */
  9. #include <sys/socket.h>
  10. #include <netinet/in.h>
  11. #include <net/if.h>
  12. #include <net/soioctl.h>
  13. #include <arpa/inet.h>
  14. #include <errno.h>
  15. #include <getopt.h>    /* for options */
  16.  
  17. #include <sys/types.h>    /* for times */
  18. #include <sys/times.h>
  19. #include <sys/param.h>
  20.  
  21. #include "cycles.h"
  22.  
  23. /* zip is way cool -> cycle-search == colours all over the place */
  24.  
  25. #define no_M_DEBUG
  26.  
  27. /* prototypes for local fns */
  28. int find_others(void);
  29. int setup_mcast_io(char *, u_short , u_short , char *);
  30. int recv_mcast(int , void *, int );
  31. void send_mcast(int , void *, int );
  32. int recv_full(void);
  33.  
  34. /* 
  35.  * Note: these values are chosen not to collide with known multicast 
  36.  * protocols and ports, but they might be wrong...
  37.  * The group address is chosen so that it won't be forwarded beyond
  38.  * the local (sub)network.
  39.  */
  40.  
  41. #define DEFAULT_PORT    8222
  42. #define DEFAULT_GROUP    "225.13.13.250"
  43.  
  44. struct sockaddr_in addr;
  45. int s;                  /* socket for comms */
  46. int full[CYCLES];       /* true if received full info from this id */
  47. clock_t last_time[CYCLES];  /* the time a packet was last recieved from this bike */
  48. static char g_group[32], g_interface[32];    /* multicast options... */
  49. static u_short g_ttl, g_port;
  50.  
  51. extern CYCLE *good, bike[CYCLES];
  52. extern int used[CYCLES], robot[CYCLES];
  53.  
  54. void parse_args(int argc, char **argv) {
  55.     int c, errflag = 0;
  56.     extern char *optarg;
  57.     extern int optind, opterr;
  58.  
  59.     /* set default communication parameters */
  60.     sprintf(g_group, "%s", DEFAULT_GROUP);
  61.     sprintf(g_interface, "%s", "");
  62.     g_ttl = 1;
  63.     g_port = DEFAULT_PORT;
  64.  
  65.     /* parse command line args */
  66.     while ((c = getopt(argc, argv, "i:t:")) != -1)
  67.     switch(c) {
  68.     case 'i':
  69.         sprintf(g_interface, "%s", optarg);
  70.         break;
  71.     case 't':
  72.         g_ttl = (u_short)atoi(optarg);
  73.         break;
  74.         default:
  75.             errflag++;
  76.             break;
  77.     }
  78.     if (errflag) {
  79.     printf("usage: %s [ -i interface ] [ -t ttl ]\n", argv[0]);
  80.     exit(1);
  81.     }
  82. }
  83.  
  84. /*
  85.  * open a multicast socket
  86.  */
  87. void init_comms(void) {
  88.     s = setup_mcast_io(g_group, g_port, g_ttl, g_interface);
  89. }
  90.  
  91.  
  92. /*
  93.  * loop waiting for big packets from all players
  94.  */
  95. int wait_for_replies(void) {
  96.     int new_user;
  97.  
  98.     /* loop here waiting 'til we have "full" from all */
  99. #ifdef M_DEBUG
  100. printf("recving full's...\n");
  101. #endif
  102.     new_user = recv_full();
  103.  
  104. #ifdef M_DEBUG
  105. printf("go play...\n");
  106. #endif
  107.     /* our work here is done - go play games */
  108.     return(new_user);
  109. }
  110.  
  111.  
  112. /*
  113.  * read the network for a second or so and build up a list of players
  114.  * set our id to be a free slot if there is one, otherwise exit
  115.  * initialise our position data
  116.  */
  117. void init_network(int *num_robots) {
  118.     int id, i, cnt;
  119.  
  120.     if ((id = find_others()) == -1) {
  121.     printf("sorry - game is full\n");
  122.     exit(0);
  123.     }
  124. #ifdef M_DEBUG
  125. printf("our id is %d\n", id);
  126. printf("init_net: used: ");
  127. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  128. printf("\n");
  129. #endif
  130.  
  131.     /* ok, we're in the game... */
  132.     good = &bike[id];
  133.     init_pos(good);
  134.     good->id = id;
  135.     good->type = PERSON;
  136.     used[id] = 1;
  137.     full[id] = 1;
  138.  
  139.     /* and so are our robots */
  140.     cnt = 0;
  141.     for (i = 0; i < CYCLES; i++) {
  142.     if (robot[i])
  143.         if (cnt < *num_robots) {
  144.         cnt++;
  145.         init_pos(&bike[i]);
  146.         bike[i].id = i;
  147.         used[i] = 1;
  148.         full[i] = 1;
  149.         }
  150.         else
  151.         robot[i] = 0;
  152.     }
  153. }
  154.  
  155.  
  156. /*
  157.  * loop waiting for a "full" packet from all
  158.  */
  159. int recv_full() {
  160.     int i;
  161.     struct tms t;
  162.     clock_t clicks;
  163.     int new_user = 0;
  164.  
  165. #ifdef M_DEBUG
  166. printf("TOP\n");
  167. printf("recv full: used ");
  168. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  169. printf("\n");
  170. printf("recv full: full ");
  171. { int i; for (i=0;i<CYCLES;i++) printf("%d ", full[i]); }
  172. printf("\n");
  173. #endif
  174.  
  175.     /* loop again waiting for info from all other players */
  176.     clicks = times(&t) + 1.5*HZ;        /* look for 1.5 seconds */
  177.     for (i = 0; times(&t) < clicks; i++)
  178.     if (get_and_sort_mcasts()) new_user = 1;
  179.  
  180. #ifdef M_DEBUG
  181. printf("AFTER GET AND SORT\n");
  182. printf("recv full: new_user found? %d\n",  new_user);
  183. printf("recv full: used ");
  184. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  185. printf("\n");
  186. printf("recv full: full ");
  187. { int i; for (i=0;i<CYCLES;i++) printf("%d ", full[i]); }
  188. printf("\n");
  189. #endif
  190.  
  191.     /*
  192.      * if after this we haven't got "full"s from all "used" by this
  193.      * time then flag the "used"s as dead 'cos they're too slow
  194.      */
  195.     for (i = 0; i < CYCLES; i++)
  196.     if (i != good->id && used[i] && !full[i] && !robot[i])
  197.         used[i] = 0;
  198.  
  199. #ifdef M_DEBUG
  200. printf("AFTER ELIMATED no_returns\n");
  201. printf("recv full: used ");
  202. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  203. printf("\n");
  204. printf("recv full: full ");
  205. { int i; for (i=0;i<CYCLES;i++) printf("%d ", full[i]); }
  206. printf("\n");
  207. #endif
  208.  
  209.     return(new_user);
  210. }
  211.  
  212.  
  213. /*
  214.  * see who else is out there. returns a free id #, or -1 if game full
  215.  * return as many robot ids as possible,  but don't worry too much
  216.  * if we can't do them all...
  217.  */
  218. int find_others(void) {
  219.     int i, id;
  220.     struct tms t;
  221.     clock_t clicks;
  222.     CYCLE tmp;
  223.  
  224.     /* zero the used, robot structs */
  225.     for (i = 0; i < CYCLES; i++) {
  226.     used[i] = 0;
  227.     full[i] = 0;
  228.     robot[i] = 0;
  229.     }
  230.  
  231.     /* loop waiting for info from all other players */
  232.     clicks = times(&t) + 1.5*HZ;        /* look for 1.5 second */
  233.     for (i = 0; times(&t) < clicks; i++)
  234.     if (recv_mcast(s, &tmp, sizeof(tmp)) != -1) used[tmp.id] = 1;       
  235.  
  236. #ifdef M_DEBUG
  237. printf("find: used: ");
  238. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  239. printf("\n");
  240. #endif
  241.  
  242.     id = -1;
  243.     /* return unused slots, if any */
  244.     for (i = 0; i < CYCLES; i++) {
  245.     if (!used[i])
  246.         if (id == -1)   /* allocate our id first */
  247.         id = i;
  248.         else
  249.         robot[i] = 1;
  250.     }
  251.  
  252.     return(id);
  253. }
  254.  
  255.  
  256. void send_mcast(int fd, void *message, int size) {
  257.     int cnt;
  258.  
  259.     cnt = sendto(fd, message, size, 0, &addr, sizeof(addr));
  260. #ifdef M_DEBUG
  261. if (cnt > 100)
  262.  printf("sent mcast: %d id %d aliv? %d\n", cnt, ((CYCLE *)message)->id, ((CYCLE *)message)->alive);
  263. #endif
  264.     if (cnt < 0) {
  265.     perror("sendto");
  266.     exit(1);
  267.     }
  268. }
  269.  
  270.  
  271. void send_full_mcast(CYCLE *C) {
  272. #ifdef M_DEBUG
  273. printf("send: full ");
  274. { int i; for (i=0;i<CYCLES;i++) printf("%d ", full[i]); }
  275. printf("\n");
  276. printf("send: used ");
  277. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  278. printf("\n");
  279. #endif
  280.     send_mcast(s, C, FULL_PACKET);
  281. }
  282.  
  283.  
  284. void send_all_full_mcast() {
  285.     int i;
  286.  
  287. #ifdef M_DEBUG
  288. printf("send: full ");
  289. { int i; for (i=0;i<CYCLES;i++) printf("%d ", full[i]); }
  290. printf("\n");
  291. printf("send: used ");
  292. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  293. printf("\n");
  294. #endif
  295.     /* send us */
  296.     send_mcast(s, good, FULL_PACKET);
  297.  
  298.     /* and our robots */
  299.     for (i = 0; i < CYCLES; i++)
  300.     if (robot[i])
  301.         send_mcast(s, &bike[i], FULL_PACKET);
  302. }
  303.  
  304.  
  305. void send_update_mcast() {
  306.     int i;
  307.  
  308.     /* send us */
  309.     send_mcast(s, good, SHORT_PACKET);
  310.  
  311.     /* and our robots */
  312.     for (i = 0; i < CYCLES; i++)
  313.     if (robot[i])
  314.         send_mcast(s, &bike[i], SHORT_PACKET);
  315. }
  316.  
  317.  
  318. int recv_mcast(int fd, void *message, int size) {
  319.     int cnt;
  320.     struct sockaddr_in fromaddr;
  321.     int fromaddrlen = sizeof(fromaddr);
  322.  
  323.     cnt = recvfrom(fd, message, size, 0, &fromaddr, &fromaddrlen);
  324. #ifdef M_DEBUG
  325. if (cnt > 100)
  326.  printf("recv'd mcast: %d id %d alive? %d\n", cnt, ((CYCLE *)message)->id, ((CYCLE *)message)->alive);
  327. #endif
  328.     if (cnt < 0 && errno != EWOULDBLOCK) {
  329.     perror("recvfrom");
  330.     exit(1);
  331.     }
  332.     return(cnt);
  333. }
  334.  
  335.  
  336. /*
  337.  * check if cycle hasn't been heard from for a second or so and
  338.  * kill it off if it hasn't
  339.  * NOTE: the timeout muct be greater than the startup sequence waits
  340.  */
  341. void kill_dead_cycle(void) {
  342.     int i;
  343.     struct tms t;
  344.  
  345.     for (i = 0; i < CYCLES; i++)
  346.     if (used[i] && i != good->id && !robot[i] && last_time[i] + NET_TIMEOUT*HZ < times(&t)) {
  347.         bike[i].quit = 1;
  348.         used[i] = 0;
  349.         full[i] = 0;
  350.         printf("cycles: killed \"%s\" id %d: lost contact for %g seconds\n", bike[i].name, bike[i].id, (float)NET_TIMEOUT);
  351.     }
  352. }
  353.  
  354.  
  355. /*
  356.  * receive multicast packet handler
  357.  *  - gets data from network
  358.  *  - packs data into cycle structs
  359.  *  - handles both long and short (update) packets
  360.  *  - return 1 if new user has arrived, 0 otherwise
  361.  */
  362. int get_and_sort_mcasts(void) {
  363.     CYCLE tmp;
  364.     int i, len, id, new_user;
  365.     struct tms t;
  366.  
  367.     new_user = 0;
  368.  
  369.     while((len = recv_mcast(s, &tmp, sizeof(tmp))) != -1) {
  370.     id = tmp.id;
  371.  
  372.     /* filter out packets from ourself */
  373.     if (id == good->id) {
  374.         printf("error: packet from ourself %d  ... committing suicide\n", len);
  375.         good->quit = 1;
  376.         new_user = 1;
  377.     }
  378.  
  379.     /* and from our robots */
  380.     for (i = 0; i < CYCLES; i++) {
  381.         if (robot[i] && i == id) {
  382.         /* drop packets from ourself */
  383.         printf("error: packet from our robots %d  ... downer\n", len);
  384.         bike[i].alive = 0;
  385.         new_user = 1;
  386.         continue;
  387.         }
  388.     }
  389.  
  390.     /* remember the time this packet arrived */
  391.     last_time[id] = times(&t);
  392.  
  393.     /*
  394.      * if new, _and_ have got a full packet, then add to
  395.      * used list and flag new_user
  396.      */
  397.     used[id] = 1;
  398.     if (!full[id] && tmp.alive) new_user = 1;
  399.  
  400.     /* if someone is quiting remove player from list */
  401.     if (tmp.quit) {
  402.         used[id] = 0;
  403.         full[id] = 0;
  404.         bzero(&bike[id], sizeof(CYCLE));
  405.     }
  406.  
  407.     /*
  408.      * if short packet then check that have previously
  409.      * received full data and if so, update cycle struct
  410.      */
  411.     if (len == SHORT_PACKET) {
  412.         if (full[id]) {
  413.         int tp;
  414.  
  415.         /* update cycle data and trail */
  416.         bcopy((void *)&tmp, (void *)&bike[id], (int)SHORT_PACKET);
  417.         tp = bike[id].trail_ptr;
  418.         bcopy((void *)&bike[id].trail_update, (void *)&bike[id].trail[tp], (int)sizeof(POINT));
  419.         }
  420.     }
  421.     /*
  422.      * else if long packet then copy over into cycle struct and
  423.      * flag full received from this id
  424.      */
  425.     else if (len == FULL_PACKET) {
  426.         bcopy((void *)&tmp, (void *)&bike[id], (int)FULL_PACKET);
  427.         full[id] = 1;
  428. #ifdef M_DEBUG
  429. printf("get_sort BIG: full ");
  430. { int i; for (i=0;i<CYCLES;i++) printf("%d ", full[i]); }
  431. printf("\n");
  432. printf("get_sort BIG: used ");
  433. { int i; for (i=0;i<CYCLES;i++) printf("%d ", used[i]); }
  434. printf("\n");
  435. #endif
  436.     }
  437.     else {
  438.         printf("cycles: get_and_sort_mcasts: weird packet length %d - wrong version bucko??\n", len);
  439.     }
  440.  
  441.     /* if dead then set full to 0 */
  442.     if (!tmp.alive) full[id] = 0;
  443.  
  444.     }
  445.  
  446.     return(new_user);
  447. }
  448.  
  449.  
  450. /*
  451.  * setup normal mcast routing - default calling is
  452.  *  - mostly taken from 4Dgifts mcast.c
  453.  */
  454. int setup_mcast_io(char *group, u_short port, u_short ttl, char *interface) {
  455.     int            fd, i, on;
  456.     struct ip_mreq    mreq;
  457.     u_char        loop = 0;
  458.     struct in_addr    ifaddr;
  459.     struct in_addr    grpaddr;
  460.     u_char        t_ttl;
  461.  
  462.     t_ttl = ttl;    /* dunno why need this... */
  463.  
  464. #if 0
  465. printf("t %d p %d i %s g %s\n", ttl, port, interface, group);
  466. #endif
  467.  
  468.     on = 1;
  469.     grpaddr.s_addr = inet_addr(group);
  470.  
  471.     if (!IN_MULTICAST(grpaddr.s_addr)) {
  472.     fprintf(stderr, "Invalid multicast group address: %s\n", group);
  473.     exit(1);
  474.     }
  475.  
  476.     if (port != DEFAULT_PORT)
  477.     fprintf(stderr, "Warning: port %d may be in use, check /etc/services for defined ports\n", (int)port);
  478.  
  479.     fd = socket(AF_INET, SOCK_DGRAM, 0);
  480.     if (fd < 0) {
  481.         perror("socket");
  482.         exit(1);
  483.     }
  484.  
  485.     bzero(&addr, sizeof(addr));
  486.     addr.sin_family = AF_INET;
  487.     addr.sin_addr.s_addr = htonl(INADDR_ANY);
  488.     addr.sin_port = htons(port);
  489.  
  490.     ifaddr.s_addr = htonl(INADDR_ANY);
  491.  
  492.     if (strcmp(interface, "")) {
  493.     /*
  494.      * Make sure the specified interface exists and is capable of doing
  495.      * multicasting.
  496.      */
  497.  
  498.     struct ifconf ifc;
  499.     struct ifreq *ifr;
  500.     char buf[BUFSIZ];
  501.  
  502. #ifdef M_DEBUG
  503. printf("interface active %s\n", interface);
  504. #endif
  505.  
  506.     ifc.ifc_len = sizeof(buf);
  507.     ifc.ifc_buf = buf;
  508.     if (ioctl(fd, (int)SIOCGIFCONF, (char *)&ifc) < 0) {
  509.         perror("ioctl SIOCGIFCONF");
  510.         exit(1);
  511.     }
  512.  
  513.     ifr = ifc.ifc_req;
  514.     for (i = ifc.ifc_len/sizeof(*ifr); --i >= 0; ifr++) {
  515.         if (ifr->ifr_addr.sa_family != AF_INET)
  516.         continue;
  517.         if (strncmp(ifr->ifr_name, interface, strlen(ifr->ifr_name)) == 0) {
  518.  
  519.         /* Obtain the interface's assigned network address */
  520.         ifaddr = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
  521.  
  522.         if (ioctl(fd, (int)SIOCGIFFLAGS, (char *) ifr) < 0) {
  523.             perror("ioctl SIOCGIFFLAGS");
  524.             exit(1);
  525.         }
  526.         if (!(ifr->ifr_flags & IFF_MULTICAST)) {
  527.             fprintf(stderr,
  528.             "%s: interface doesn't support multicasting\n",
  529.             interface);
  530.             exit(1);
  531.         }
  532.  
  533.         /* Specify the interface to use when sending packets */
  534.         if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, sizeof(ifaddr)) < 0) {
  535.             perror("setsockopt ifaddr");
  536.             exit(1);
  537.         }
  538.         break;
  539.         }
  540.     }
  541.     if (ifaddr.s_addr == htonl(INADDR_ANY)) {
  542.         fprintf(stderr, "%s: invalid or unknown interface\n", interface);
  543.         exit(1);
  544.     }
  545.     }
  546.  
  547.     /* disable loop in multicast mode */
  548.     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop))) {
  549.     perror("setsockopt loop");
  550.     exit(1);
  551.     }
  552.  
  553.     /* turn on non-blocking i/o */
  554.     if (ioctl(fd, (int)FIONBIO, &on) < 0) {
  555.     perror("non blocking");
  556.     exit(1);
  557.     }
  558.  
  559.     /* set time to live */
  560.     if (setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &t_ttl, sizeof(t_ttl))) {
  561.     perror("setsockopt ttl");
  562.     exit(1);
  563.     }
  564.  
  565. #if 0
  566.     /*
  567.      * DEBUG:
  568.      * Allow multiple instances of this program to listen on the same
  569.      * port on the same host. By default, only 1 program can bind
  570.      * to the port on a host.
  571.      */
  572.     if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) {
  573.     perror("setsockopt REUSEPORT");
  574.     exit(1);
  575.     }
  576. #endif
  577.  
  578.     if (bind(fd, &addr, sizeof(addr)) < 0) {
  579.     perror("bind");
  580.     exit(1);
  581.     }
  582.  
  583.     mreq.imr_multiaddr = grpaddr;
  584.     mreq.imr_interface = ifaddr;
  585.     if (setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
  586.     perror("setsockopt mreq");
  587.     exit(1);
  588.     }
  589.  
  590.     /* can't put this line up above - bind fails. why??? */
  591.     addr.sin_addr = grpaddr;
  592.  
  593.     return(fd);
  594. }
  595.